import { LLMChatMessage } from "../type/llmType.js";
import { writeFileSync, readFileSync, mkdirSync, existsSync } from "fs";
import { AIAPI } from "../type/llmType.js";
import { ConsoleColor } from "../utils/consoleColor.js";
import { truncateMiddle } from "../utils/string/formatString.js";

export class ContentManager {
  private _contents: Array<LLMChatMessage> = [];
  private _removeContents: number;
  private _maxContents: number;
  private _name: string;

  constructor(name: string = "Assistant", maxContents: number = 20, removeContents: number = 1) {
    this._name = name;
    this._maxContents = maxContents;
    this._removeContents = removeContents;
    mkdirSync(`./bots/${this._name}/contents`, { recursive: true });
    this._loadFile();
  }

  private _chatSummaryInterval: number = 5;
  private _chatCount: number = 0;
  private _summary: string = "";
  private _api: AIAPI | null | undefined;
  summaryConfig(chatSummaryInterval = 5, api?: AIAPI) {
    this._chatSummaryInterval = chatSummaryInterval;
    this._api = api;
  }

  addContent(message: LLMChatMessage): void {
    this._contents.push(message);
    if (this._contents.length > this._maxContents) {
      this._contents.splice(0, this._removeContents);
      while (this._contents.length > 0 && this._contents[0] && this._contents[0].role !== "user") {
        this._contents.shift();
      }
    }
    if (message.role === "user") ++this._chatCount;
    if (this._chatCount >= this._chatSummaryInterval && this._api) {
      this._chatCount = 0;
      this._updateSummary();
    }
    this._saveFile();
  }

  clearContents(): void {
    this._contents = [];
    this._summary = "";
    this._saveFile();
  }

  getContents(): Array<LLMChatMessage> {
    return [...this._contents];
  }

  getSummary(): string {
    return this._summary;
  }

  _saveFile(): void {
    writeFileSync(
      `./bots/${this._name}/contents/contents.json`,
      JSON.stringify({
        summary: this._summary,
        contents: this._contents,
      }),
      "utf-8"
    );
  }

  _loadFile(): void {
    if (existsSync(`./bots/${this._name}/contents/contents.json`)) {
      let data;
      let obj;
      try {
        data = readFileSync(`./bots/${this._name}/contents/contents.json`, "utf-8");
        obj = JSON.parse(data);
      } catch (error) {
        console.error(ConsoleColor.red(`BOT[${this._name}]读取上下文失败!: ${error}`));
      }
      this._summary = obj?.summary ?? "";
      this._contents = obj?.contents ?? [];
    }
  }

  async _updateSummary(): Promise<void> {
    if (!this._api) return;
    let contents = [...this._contents];
    contents.push({
      role: "user",
      content: `你现在将作为一个总结分析模块，通过分析列表中的对话和自己的原始总结，来扩充或修改现有的总结。
请严格遵守：
1. 保留原始总结，除非你认为对其进行简化后不影响信息量或某些原始总结需要更新
2. 将生成内容添加在原始总结（或者被你进行过调整的原始总结）的后面
3. 若你认为当前上下文并不需要生成新的总结，保留原始总结即可
4. 若没有信息表明原始总结需要修改/删除，请务必保留原始总结，并紧接其后面生成新的记忆内容
生成内容要求：
1. 严格控制字数在50-200字内，尽可能精简
2. 仅保留对未来对话至关重要的信息
3. 使用第一人称视角撰写，仿佛是你自己在记录对话记忆
4. 使用极简句式，省略不必要的修饰词，禁止使用颜文字和括号描述动作
5. 信息应当是从你的角度了解到的用户信息
6. 格式为简洁的要点，可用分号分隔不同信息
仅返回你扩充/修改后的总结内容，不要包含任何解释。 `,
    });
    try {
      const result = await this._api.chat(contents, 0.3);
      result.trim();
      if (result !== "") {
        this._summary = result;
        this._saveFile();
        console.log(
          ConsoleColor.yellow(
            `BOT[${this._name}]更新总结(每${this._chatSummaryInterval}轮一次): ${truncateMiddle(
              this._summary,
              100,
              100
            )}`
          )
        );
      }
    } catch (error) {
      console.error(ConsoleColor.red(`BOT[${this._name}]更新总结失败!: ${error}`));
    }
  }
}
